<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>超级电容启动电源</title>
    <style>
        body {
            font-size: 16px;
            height: 100vh;
            padding: 0;
            margin: 0;
            border: 0;
        }
        .tips {
            width: 16px;
            height: 16px;
            border: 1px solid #ccc;
            border-radius: 20px;
            color: #fff;
            background-color: #ccc;
            margin: 0;
            padding: 0;
            display: inline-flex;
            font-size: 12px;
            justify-content: center;
            align-items: center;
            user-select: none;
        }
        #info {
            border: 1px solid #ccc;
            padding: 10px;
            width: 600px;
            color: rgb(128, 128, 128);
        }
        .line {
            display: flex;
            justify-content: flex-start;
            margin-top: 30px;
        }
        .line div {
            width: 150px;
        }
        .green {
            color: forestgreen;
        }
        .red {
            color: red;
        }
        .blue {
            color: blue;
        }
        .orange {
            color: orange;
        }
        .bold {
            font-weight: bold;
        }
        #opt {
            border: 1px solid #ccc;
            padding: 10px;
            width: 600px;
            margin-top: 20px;
        }
        button {
            width: 80px;
            height: 30px;

        }
        #opt select {
            min-width: 80px;
            height: 30px;
        }
        #opt input {
            width: 80px;
            height: 20px;
        }
        .grey {
            color: grey;
        }
        #tips-modal {
            position: absolute;
            top: 0;
            left: 0;
            z-index: 100;
            width: 200px;
            min-height: 40px;
            border: solid 1px #ccc;
            background-color: #fff;
            padding: 10px;
            font-size: 14px;
            display: none;
            box-shadow: 0 0 10px #ccc;
        }
    </style>
</head>
<body>
<button id="connect" style="margin: 20px 200px; width: 120px;">连接蓝牙设备</button>
<div style="display: block" id="test-info">
    <input value="12.04-12.21-0.10-17.81-28-15.00-100-0-0-1-2-0-6-2-80-0-0" id="readValue" style="width: 400px"/>
    <button id="read" onclick="read()">读取</button>
    <button id="wite" onclick="writeData(1)">测试写1</button>
</div>
<div id="info">
    <span>电量：<span id="power" class="red bold" style="font-size: 40px">--</span>%</span>
    <div class="line">
        <div >
            电瓶电压：<span id="bat-v" class="green bold">--</span>V
        </div>
        <div >
            USB电压：<span id="usb-v" class="green bold">--</span>V
        </div>
        <div >
            电容电压：<span id="cap-v" class="green bold">--</span>V
        </div>
        <div >
            电容温度：<span id="cap-c" class="green bold">--</span>&#8451;
        </div>
    </div>
    <div class="line">
        <div >
            充电速度：<span id="cha-s" class="green bold">--</span>%
        </div>
        <div >
            截止电压：<span id="cha-v" class="green bold">--</span>V
            <p class="tips" onclick="showTips(event, '车载稳压使用模式下电容的充满截止电压')" >?</p>
        </div>
        <div >
            照明亮度：<span id="lig-b" class="green bold">--</span>%
        </div>
        <div >
            照明状态：<span id="lig-s" class="bold">--</span>
        </div>
    </div>
    <div class="line">
        <div >
            放电状态：<span id="dis-s" class="bold">--</span>
        </div>
        <div >
            放电保护：<span id="dis-l" class="bold">--</span>
        </div>
        <div >
            放电模式：<span id="dis-m" class="bold blue">--</span>
        </div>
        <div >
            用途模式：<span id="mod" class="bold blue">--</span>
        </div>

    </div>
    <div class="line">
        <div  style="width: 200px;">
            自动放电灵敏度：<span id="auto-v" class="green bold">--</span>
            <p class="tips" onclick="showTips(event, '值越大越容易触发救援模式的自动放电')" >?</p>
        </div>
        <div style="width: 300px;">
            车载放电灵敏度：<span id="car-v"  class="green bold">--</span>
            <p class="tips" onclick="showTips(event, '值越大越早触发车载模式的接通放电，0表示电容与电瓶电压相等时无冲击接通')">?</p>
        </div>
    </div>
</div>
<div id="opt">
    <div>
        <button onclick="changeLigS()" id="light_btn">开灯</button>

        <button onclick="disconnect()" id="disconnect_btn" style="margin-left: 30px; width: 100px;">断开蓝牙连接</button>
        <button onclick="turnOff()" id="turnoff_btn" style="margin-left: 30px">关机</button>
    </div>

    <div style="margin-top: 30px;">

        <button onclick="disAuto()" id="auto_btn" >自动放电</button>
        <button onclick="disTimer()" id="timer_btn" style="margin-left: 30px; width: 100px;">倒计时放电</button>
        <button onclick="disManu()" id="manu_btn" style="margin-left: 30px">手动放电</button>
        <button onclick="closeDis()" id="off_btn" style="margin-left: 30px">关闭放电</button>
    </div>

    <div style="margin-top: 30px;">
        放电模式：
        <select id="mode_opt" >
            <option value="0">有电瓶</option>
            <option value="1">无电瓶</option>
            <option value="2">全手动</option>
        </select>
        <button onclick="changeMod()" id="mode_btn" style="width: 60px">更改</button>
    </div>

    <div style="margin-top: 30px;">
        用途模式：
        <select id="mode2_opt" style="">
            <option value="0">应急救援</option>
            <option value="1">车载稳压</option>
        </select>
        <button onclick="changeMod2()" id="mode2_btn" style="width: 60px">更改</button>
    </div>

    <div style="margin-top: 30px;">
        充电速度：
        <input type="number" id="cha-s-in" value="" min="0" max="100">%
        <button onclick="changeChaS()" id="cha-s-btn" style="width: 60px">发送</button>
        <span class="grey">取值范围：0-100</span>
    </div>
    <div style="margin-top: 30px;">
        照明亮度：<input type="number" id="lig-b-in" value="" min="1" max="100">%
        <button onclick="changeLigB()" id="lig-b-btn" style="width: 60px">发送</button>
        <span class="grey">取值范围：1-100</span>
    </div>
    <div style="margin-top: 30px;">
        充电截止电压：
        <input type="number" id="cha-v-in" value="" min="0.0" max="15.0">V
        <button onclick="changeChaV()" id="cha-v-btn" style="width: 60px">发送</button>

        <span class="grey">取值范围：0.0-15.0</span>
        <p class="tips" onclick="showTips(event, '车载稳压使用模式下电容的充满截止电压')" >?</p>
    </div>
    <div style="margin-top: 30px;">
        自动放电灵敏度：
        <input type="number" id="auto-v-in" value="" min="1" max="9">
        <button onclick="changeAutoV()" id="auto-v-btn" style="width: 60px">发送</button>
        <span class="grey">取值范围：1-9</span>
        <p class="tips" onclick="showTips(event, '值越大越容易触发救援模式的自动放电')" >?</p>
    </div>
    <div style="margin-top: 30px;">
        车载放电灵敏度：
        <input type="number" id="car-v-in" value="" min="0" max="9">
        <button onclick="changeCarV()" id="car-v-btn" style="width: 60px">发送</button>
        <span class="grey">取值范围：0-9</span>
        <p class="tips" onclick="showTips(event, '值越大越早触发车载模式的接通放电，0表示电容与电瓶电压相等时无冲击接通')">?</p>
    </div>
</div>
<div id="tips-modal">

</div>
<script>
    // 蓝牙连接类
    class BlueToothUtil {
        constructor(disCallback) {
            this.device = null;
            this.disCallback = disCallback;
            this.onDisconnected = this.onDisconnected.bind(this);
        }

        async request() {
            let options = {
                "filters": [{
                    "namePrefix": "NBH",
                    // "namePrefix": "真我",
                }],
                "optionalServices": [0xFFF0]
            };
            this.device = await navigator.bluetooth.requestDevice(options);
            if (!this.device) {
                throw "No device selected";
            }
            this.device.addEventListener('gattserverdisconnected', this.onDisconnected);
        }

        async connect() {
            if (!this.device) {
                return Promise.reject('Device is not connected.');
            }
            return await this.device.gatt.connect();
        }

        async readOrder() {
            const service = await this.device.gatt.getPrimaryService(0xFFF0);
            const characteristic = await service.getCharacteristic(0xFFF1);
            await characteristic.readValue();
        }

        async writeOrder(data) {
            const service = await this.device.gatt.getPrimaryService(0xFFF0);
            const characteristic = await service.getCharacteristic(0xFFF2);
            await characteristic.writeValue(data);
        }

        async startOrderNotifications(listener) {
            const service = await this.device.gatt.getPrimaryService(0xFFF0);
            const characteristic = await service.getCharacteristic(0xFFF1);
            await characteristic.startNotifications();
            characteristic.addEventListener('characteristicvaluechanged', listener);
        }

        async stopOrderNotifications(listener) {
            const service = await this.device.gatt.getPrimaryService(0xFFF0);
            const characteristic = await service.getCharacteristic(0xFFF1);
            await characteristic.stopNotifications();
            characteristic.removeEventListener('characteristicvaluechanged', listener);
        }

        disconnect() {
            if (!this.device) {
                return Promise.reject('Device is not connected.');
            }
            return this.device.gatt.disconnect();
        }

        onDisconnected() {
            if (this.disCallback) {
                this.disCallback();
            }
            console.log('Device is disconnected.');
        }
    }
</script>
<script>
    if (/Mobi|Android|iPhone/i.test(navigator.userAgent)) {
        window.location.replace('mobile.html');

    }
    let isConnected = false;
    let isFirst = true;
    let isTimer = false; // 是否正在倒计时
    let cancelStatus = false;
    const blueToothUtil = new BlueToothUtil(() => {
        alert('蓝牙设备已断开连接');
        isConnected = false;
        optDiv.style.display = 'none';
        connectBtn.style.display = 'block';
    });

    const chaSInput = document.querySelector('#cha-s-in');
    const ligBInput = document.querySelector('#lig-b-in');
    const chaVInput = document.querySelector('#cha-v-in');
    const autoVInput = document.querySelector('#auto-v-in');
    const carVInput = document.querySelector('#car-v-in');

    const ligBtn = document.querySelector('#light_btn');
    const ligSText = document.querySelector('#lig-s');

    const autoBtn = document.querySelector('#auto_btn');
    const timerBtn = document.querySelector('#timer_btn');
    const manuBtn = document.querySelector('#manu_btn');
    const offBtn = document.querySelector('#off_btn');
    const turnoffBtn = document.querySelector('#turnoff_btn');
    const connectBtn = document.querySelector('#connect');

    const modeOpt = document.querySelector('#mode_opt');
    const mode2Opt = document.querySelector('#mode2_opt');
    const tipsModal = document.querySelector('#tips-modal');

    const optDiv = document.querySelector('#opt');
    optDiv.style.display = 'none';

    connectBtn.addEventListener('click', async () => {
        if(isConnected) {
            return;
        }

        const res = await connect();
        if(!res) {
            return;
        }
        isConnected = true;
        optDiv.style.display = 'block';
        connectBtn.style.display = 'none';
    });

    async function disconnect() {
        await blueToothUtil.disconnect();
        isConnected = false;
        optDiv.style.display = 'none';
        connectBtn.style.display = 'block';
    };

    function showTips(event, msg) {
        const x = event.clientX;
        const y = event.clientY;
        tipsModal.style.display = 'block';
        tipsModal.style.left = `${x}px`;
        tipsModal.style.top = `${y}px`;
        tipsModal.innerText = msg;
        event.stopPropagation();
    }
    document.body.addEventListener('click', () => {
        tipsModal.innerText = '';
        tipsModal.style.display = 'none';
    });


    async function connect() {
        let res = false;
        try {
            await blueToothUtil.request();
            await blueToothUtil.connect();

            await blueToothUtil.startOrderNotifications(data => {
                const decoder = new TextDecoder('utf-8');
                const value =  decoder.decode(data.target.value);
                formatValue(value);
                console.log(value);
            })
            return true;
        } catch(error) {
            console.error(error);
        }
        return res;
    }

    function read() {
        setInterval(() => {
            const value = document.querySelector('#readValue').value;
            formatValue(value);
        }, 500);
        optDiv.style.display = 'block';
    }

    function formatValue(value) {
        const list = value.split('-');
        if (list.length !== 17) {
            return;
        }
        const batV = list[0];
        const usbV = list[1];
        const capV = list[2];
        const capC = list[3];

        const chaS = list[4];
        const chaV = list[5];
        const ligB = list[6];
        const ligS = list[7];

        const disS = list[8]; // 放电状态 0：关闭，1：开启
        const disL = list[9]; // 保护状态 0：关闭，1：开启
        const disM = list[10]; // 放电模式 0：有电瓶，1：无电瓶 2：全手动
        const mod = list[11]; // 用途模式 0: 应急，1：车载

        const autoV = list[12];
        const carV = list[13];
        const power = list[14];
        const autoFlag = list[15]; // 自动放电标志 0：关闭，1：开启
        const timerFlag = list[16]; // 定时放电标志 0：关闭，1：开启
        isTimer = parseInt(timerFlag) === 1;
        cancelStatus = parseInt(timerFlag) === 0;

        document.querySelector('#cap-v').innerText = parseFloat(capV).toFixed(1);
        document.querySelector('#power').innerText = power;
        document.querySelector('#cha-s').innerText = chaS;
        document.querySelector('#cha-v').innerText = parseFloat(chaV).toFixed(1);;
        document.querySelector('#lig-b').innerText = ligB;
        document.querySelector('#auto-v').innerText = autoV;
        document.querySelector('#car-v').innerText = parseInt(carV) === 0 ? '自动跟随' : carV;

        if(isFirst) modeOpt.selectedIndex = parseInt(disM);
        if(isFirst) mode2Opt.selectedIndex = parseInt(mod);

        // 自动放电按钮状态
        if (parseInt(disS) === 1 || parseInt(mod) === 1 || parseInt(disL) === 1 || parseInt(timerFlag) === 1 || parseInt(autoFlag) === 1 || [1,2].includes(parseInt(disM))) {
            autoBtn.setAttribute('disabled', 'true');
        } else {
            autoBtn.removeAttribute('disabled');
        }

        // 倒计时放电按钮状态
        if (parseInt(disS) === 1 || parseInt(mod) === 1 || parseInt(disL) === 1 || parseInt(timerFlag) === 1 || parseInt(autoFlag) === 1 || [2].includes(parseInt(disM))) {
            timerBtn.setAttribute('disabled', 'true');
        } else {
            timerBtn.removeAttribute('disabled');
        }

        // 手动放电按钮状态
        if (parseInt(disS) === 1 || parseInt(mod) === 1 || parseInt(disL) === 1 || parseInt(timerFlag) === 1 || parseInt(autoFlag) === 1 || [1,0].includes(parseInt(disM))) {
            manuBtn.setAttribute('disabled', 'true');
        } else {
            manuBtn.removeAttribute('disabled');
        }

        // 关闭放电按钮状态
        if ((parseInt(disS) === 0 && parseInt(timerFlag) === 0 && parseInt(autoFlag) === 0) || parseInt(mod) === 1) {
            offBtn.setAttribute('disabled', 'true');
        } else {
            offBtn.removeAttribute('disabled');
        }

        // 关机按钮状态
        if (parseFloat(batV) > 1.0) {
            turnoffBtn.setAttribute('disabled', 'true');
        } else {
            turnoffBtn.removeAttribute('disabled');
        }

        // 填充发送输入框
        if (isFirst && chaSInput.value === '' ) {
            chaSInput.value = chaS;
        }
        if (isFirst && ligBInput.value === '') {
            ligBInput.value = ligB;
        }
        if (isFirst && chaVInput.value === '') {
            chaVInput.value = parseFloat(chaV).toFixed(1);
        }
        if (isFirst && autoVInput.value === '') {
            autoVInput.value = autoV;
        }
        if (isFirst && carVInput.value === '') {
            carVInput.value = carV
        }

        const batVText = document.querySelector('#bat-v');
        batVText.innerText = parseFloat(batV).toFixed(1);
        if (parseFloat(batV) > 30) {
            batVText.classList.add('red');
        } else {
            if (parseFloat(batV) <= 0.5) {
                batVText.innerText = '--';
            }
            batVText.classList.remove('red');
        }

        const capCText = document.querySelector('#cap-c');
        capCText.innerText = parseFloat(capC).toFixed(1);
        if (parseFloat(capC) > 90) {
            capCText.classList.add('red');
        } else {
            capCText.classList.remove('red');
        }

        const usbVText = document.querySelector('#usb-v');
        if (parseFloat(usbV) > 3.5) {
            batVText.innerText = '--';
            usbVText.innerText = parseFloat(usbV).toFixed(1);
        } else if (parseFloat(usbV) < 3.5) {
            usbVText.innerText = '--';
        } else {
            usbVText.innerText = '3.5'
        }


        if (parseInt(ligS) > 0) {
            ligSText.innerHTML = '开';
            ligSText.classList.add('green');
            ligBtn.innerHTML = '关灯';
        } else {
            ligSText.innerHTML = '关';
            ligSText.classList.remove('green');
            ligBtn.innerHTML = '开灯';
        }

        const disSText = document.querySelector('#dis-s');
        if (parseInt(disS) > 0) {
            disSText.innerHTML = '放电中';
            disSText.classList.add('red');
            disSText.classList.remove('orange');
        } else  if (parseInt(disS) === 0 && ( parseInt(autoFlag) === 1 || parseInt(timerFlag) === 1)) {
            disSText.innerHTML = '待放电';
            disSText.classList.remove('red');
            disSText.classList.add('orange');
        } else {
            disSText.innerHTML = '未放电';
            disSText.classList.remove('red');
            disSText.classList.remove('orange');

        }

        const disLText = document.querySelector('#dis-l');
        if (parseInt(disL) > 0) {
            disLText.innerHTML = '保护中';
            disLText.classList.add('green');
        } else {
            disLText.innerHTML = '未锁定';
            disLText.classList.remove('green');
        }

        const disMText = document.querySelector('#dis-m');
        if (parseInt(disM) === 2) {
            disMText.innerHTML = '全手动';
        } else if (parseInt(disM) === 1) {
            disMText.innerHTML = '无电瓶';
        } else {
            disMText.innerHTML = '有电瓶';
        }

        const modText = document.querySelector('#mod');
        if (parseInt(mod) > 0) {
            modText.innerHTML = '车载稳压';
        } else {
            modText.innerHTML = '应急救援';
        }

        isFirst = false;
    }

    // 开关灯
    function changeLigS() {
        writeData('01-001');
    }

    // 自动放电
    function disAuto() {
        writeData('02-001');
        autoBtn.setAttribute('disabled', 'true');
    }

    // 倒计时放电
    function disTimer() {
        writeData('03-001');
        timerBtn.setAttribute('disabled', 'true');
        const timer2 = setInterval(() => {
            if (isTimer) {
                clearInterval(timer2);
                disTimerInterval();
            }
        }, 200);
    }

    function disTimerInterval() {
        let time = 10;
        timerBtn.innerHTML = '等待：' + time;
        const timer = setInterval(() => {
            time--;
            if (time === 0 || cancelStatus) {
                clearInterval(timer);
                timerBtn.innerHTML = '倒计时放电';
                cancelStatus = false;
            } else {
                timerBtn.innerHTML = '等待：' + time;
            }
        }, 1000);
    }

    // 手动放电
    function disManu() {
        writeData('04-001');
        manuBtn.setAttribute('disabled', 'true');
    }

    // 关闭放电
    function closeDis() {
        writeData('05-001');
        cancelStatus = true;
        offBtn.setAttribute('disabled', 'true');
    }

    // 关机
    function turnOff() {
        writeData('13-001');
        turnoffBtn.setAttribute('disabled', 'true');
    }

    // 修改放电模式
    function changeMod() {
        const value = '06-00' + modeOpt.value;
        writeData(value);
    }

    // 修改用途模式
    function changeMod2() {
        const value = '07-00' + mode2Opt.value;
        writeData(value);
    }

    // 修改充电速度
    function changeChaS() {
        const value = parseInt(chaSInput.value);
        if (isNaN(value) || value < 0 || value > 100) {
            alert('充电速度必须在0~100之间');
            return;
        }
        let order = '08-';
        if (value < 10) {
            order += '00' + value;
        } else if (value < 100) {
            order += '0' + value;
        } else {
            order += '100';
        }
        writeData(order);
    }

    // 修改灯光亮度
    function changeLigB() {
        const value = parseInt(ligBInput.value);
        if (isNaN(value) || value < 1 || value > 100) {
            alert('灯光亮度必须在1~100之间');
            return;
        }
        let order = '09-';
        if (value < 10) {
            order += '00' + value;
        } else if (value < 100) {
            order += '0' + value;
        } else {
            order += '100';
        }
        writeData(order);
    }

    // 修改充电截止电压
    function changeChaV() {
        const value = parseFloat(chaVInput.value);
        if (isNaN(value) || value < 0 || value > 15.0) {
            alert('截止电压必须在0.0~15.0之间');
            return;
        }
        let order = '10-';
        if (value < 1.0) {
            order += '00' + (value*10).toFixed(0);
        } else if (value < 10.0) {
            order += '0' + (value*10).toFixed(0);
        } else {
            order += (value*10).toFixed(0);
        }
        writeData(order);
    }

    // 修改放电灵敏度
    function changeAutoV() {
        const value = parseInt(autoVInput.value);
        if (isNaN(value) || value < 1 || value > 9) {
            alert('自动放电灵敏度必须在1~9之间');
            return;
        }
        let order = '11-00' + value;
        writeData(order);
    }

    // 修改放电灵敏度
    function changeCarV() {
        const value = parseInt(carVInput.value);
        if (isNaN(value) || value < 0 || value > 9) {
            alert('车载放电灵敏度必须在0~9之间');
            return;
        }
        let order = '12-00' + value;
        writeData(order);
    }

    // 发送到蓝牙设备
    function writeData(str) {
        console.log('writeData', str);
        if(!isConnected) {
            return;
        }
        const byteArray = new TextEncoder().encode(str);
        const buffer = byteArray.buffer;
        blueToothUtil.writeOrder(buffer);
    }
</script>

</body>
</html>